
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

#include "sample_comm_nnie.h"
#include "sample_media_ai.h"
#include "ai_infer_process.h"
#include "yolov2_hand_detect.h"
#include "vgs_img.h"
#include "ive_img.h"
#include "misc_util.h"
#include "hisignalling.h"
#include <sys/prctl.h>
#include "hand_classify.h"

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */

#define HAND_FRM_WIDTH     640
#define HAND_FRM_HEIGHT    384
#define DETECT_OBJ_MAX     32
#define RET_NUM_MAX        4
#define DRAW_RETC_THICK    4    // Draw the width of the line
#define WIDTH_LIMIT        32
#define HEIGHT_LIMIT       32
#define IMAGE_WIDTH        224  // The resolution of the model IMAGE sent to the classification is 224*224
#define IMAGE_HEIGHT       224
#define MODEL_FILE_GESTURE    "/userdata/models/hand_classify/lesson_gesture.wk" // darknet framework wk model ，改

//pthread_t g_drawProcessThread = 0;
//pthread_t g_audioProcessThread = 0;
static int biggestBoxIndex;
static IVE_IMAGE_S img;
static DetectObjInfo objs[DETECT_OBJ_MAX] = {0};
static RectBox boxs[DETECT_OBJ_MAX] = {0};
static RectBox objBoxs[DETECT_OBJ_MAX] = {0};
static RectBox Boxs_usecellphone[DETECT_OBJ_MAX] = {0};
static RectBox cnnBoxs[DETECT_OBJ_MAX] = {0}; // Store the results of the classification network
static RecogNumInfo numInfo[RET_NUM_MAX] = {0};
static IVE_IMAGE_S imgIn;
static IVE_IMAGE_S imgDst;
static VIDEO_FRAME_INFO_S frmIn;
static VIDEO_FRAME_INFO_S frmDst;
int uartFd = 0;
static HI_U32 Num_listen = 0;
static HI_U32 Num_readbooks = 0;
static HI_U32 Num_usecellphone = 0;
//HI_CHAR drawThreadName[16] = {0};
//HI_CHAR audioThreadName[16] = {0};
//static DrawRacts racts;

static char All_num[2] = {0};

//extern int Audio_flag;

//static HI_U32 All_num[3] = {0, 0, 0};
HI_S32 Yolo2HandDetectResnetClassifyLoad(uintptr_t* model)
{
    SAMPLE_SVP_NNIE_CFG_S *self = NULL;
    HI_S32 ret;
       // 加载模型
    ret = CnnCreate(&self, MODEL_FILE_GESTURE); // CNN初始化
    *model = ret < 0 ? 0 : (uintptr_t)self;
    HandDetectInit(); // Initialize the hand detection model
    SAMPLE_PRT("Load hand detect claasify model success\n"); 
    uartFd = UartOpenInit();
    if (uartFd < 0) {
        printf("uart1 open failed\r\n");
    } else {
        printf("uart1 open successed\r\n");
    }
    
    return ret;
}

HI_S32 Yolo2HandDetectResnetClassifyUnload(uintptr_t model)
{
    CnnDestroy((SAMPLE_SVP_NNIE_CFG_S*)model);
    HandDetectExit(); // Uninitialize the hand detection model
    SAMPLE_PRT("Unload hand detect claasify model success\n");

    return 0;
}

/* Get the maximum hand */
static HI_S32 GetBiggestHandIndex(RectBox boxs[], int detectNum)
{
    HI_S32 handIndex = 0;
    HI_S32 biggestBoxIndex = handIndex;
    HI_S32 biggestBoxWidth = boxs[handIndex].xmax - boxs[handIndex].xmin + 1;
    HI_S32 biggestBoxHeight = boxs[handIndex].ymax - boxs[handIndex].ymin + 1;
    HI_S32 biggestBoxArea = biggestBoxWidth * biggestBoxHeight;

    for (handIndex = 1; handIndex < detectNum; handIndex++) {
        HI_S32 boxWidth = boxs[handIndex].xmax - boxs[handIndex].xmin + 1;
        HI_S32 boxHeight = boxs[handIndex].ymax - boxs[handIndex].ymin + 1;
        HI_S32 boxArea = boxWidth * boxHeight;
        if (biggestBoxArea < boxArea) {
            biggestBoxArea = boxArea;
            biggestBoxIndex = handIndex;
        }
        biggestBoxWidth = boxs[biggestBoxIndex].xmax - boxs[biggestBoxIndex].xmin + 1;
        biggestBoxHeight = boxs[biggestBoxIndex].ymax - boxs[biggestBoxIndex].ymin + 1;
    }

    if ((biggestBoxWidth == 1) || (biggestBoxHeight == 1) || (detectNum == 0)) {
        biggestBoxIndex = -1;
    }

    return biggestBoxIndex;
}

static void sendAllNum(char* num_list)
{
    UartSendRead(uartFd, num_list); // 拳头手势
}

// static HI_VOID* MppFrmDrawRects_entry(HI_VOID* arg){
//     //SAMPLE_PRT("entry draw proccess...\n");

//     MppFrmDrawRects(racts.frm, racts.objBox, racts.objNum , RGB888_skyBlue, DRAW_RETC_THICK);
//     return NULL;
// }

// static HI_VOID* audio_entry(HI_VOID* arg){
//     SAMPLE_PRT("entry audio proccess...\n");

//     while(Audio_flag == 1){
//         AudioTest(0, -1);
//     }

//     return NULL;

// }

// static HI_S32 MppFrmDrawRects_process(HI_VOID)
// {
//     HI_S32 s32Ret;
//     if (snprintf_s(drawThreadName, 16, 15, "drawRectsProcess") < 0) {
//         HI_ASSERT(0);
//     }
//     prctl(PR_SET_NAME, (unsigned long)g_drawProcessThread, 0, 0, 0);
//     s32Ret = pthread_create(&g_drawProcessThread, NULL, MppFrmDrawRects_entry, NULL);

//     return s32Ret;
// }

// static HI_S32 Audio_process(HI_VOID)
// {
//     HI_S32 s32Ret;
//     if (GetCfgBool("audio_player:support_audio", true)) {
//         if (snprintf_s(audioThreadName, 16, 15, "audioProcess") < 0) {
//             HI_ASSERT(0);
//         }
//         prctl(PR_SET_NAME, (unsigned long)g_audioProcessThread, 0, 0, 0);
//         s32Ret = pthread_create(&g_audioProcessThread, NULL, audio_entry, NULL);
//     }
//     return s32Ret;
// }

//改名Yolo2LessonDetectResnetClassifyCal,，传参 model = g_workPlug.model，&resizeFrm, &frm
HI_S32 Yolo2HandDetectResnetClassifyCal(uintptr_t model, VIDEO_FRAME_INFO_S *srcFrm, VIDEO_FRAME_INFO_S *dstFrm)
{
    SAMPLE_SVP_NNIE_CFG_S *self = (SAMPLE_SVP_NNIE_CFG_S*)model;
    HI_S32 resLen = 0;
    int objNum;
    int ret;
    int num_box = 0;
    //int  Boxs_usecellphone_index = 0;

    ret = FrmToOrigImg((VIDEO_FRAME_INFO_S*)srcFrm, &img);// 色彩空间转换，转换为YUV图像，保存到img中
    SAMPLE_CHECK_EXPR_RET(ret != HI_SUCCESS, ret, "hand detect for YUV Frm to Img FAIL, ret=%#x\n", ret);
   // SAMPLE_PRT("yolo2_in: \n");
//ret = Audio_process();
    objNum = HandDetectCal(&img, objs); // Send IMG to the detection net for reasoning， 返回一个目标检测数objNum，同时把检测到的目标放到obj里
    for (int i = 0; i < objNum; i++) {
        cnnBoxs[i] = objs[i].box;
        RectBox *box = &objs[i].box;
        RectBoxTran(box, HAND_FRM_WIDTH, HAND_FRM_HEIGHT,  // 如果画框不准的话，可能没有对目标进行校准
            dstFrm->stVFrame.u32Width, dstFrm->stVFrame.u32Height);
       // SAMPLE_PRT("yolo2_out: {%d, %d, %d, %d}\n", box->xmin, box->ymin, box->xmax, box->ymax);
        boxs[i] = *box;
    }
        for (int j = 0; j < objNum; j++, num_box++) {
            objBoxs[num_box] = boxs[j];
            //flag = (uint32_t)objs[j].cls;
            // if (objs[j].cls == 3u){
            // racts.frm = dstFrm;
            // racts.objBox = objBoxs;
            // racts.objNum = objNum;
            MppFrmDrawRects(dstFrm, objBoxs, objNum , RGB888_skyBlue, DRAW_RETC_THICK);
            // }
            
            SAMPLE_CHECK_EXPR_RET(ret != HI_SUCCESS, ret, "ai proccess thread creat fail:%s\n", strerror(ret));

            ret = ImgYuvCrop(&img, &imgIn, &cnnBoxs[j]);//将图片按照box大小裁剪，送到imgin中，
            SAMPLE_CHECK_EXPR_RET(ret < 0, ret, "ImgYuvCrop FAIL, ret=%#x\n", ret);
            
            if ((imgIn.u32Width >= WIDTH_LIMIT) && (imgIn.u32Height >= HEIGHT_LIMIT)) {//这里的图像大小一定要符合分类网规格，否则会降低检测精度
                COMPRESS_MODE_E enCompressMode = srcFrm->stVFrame.enCompressMode;
                ret = OrigImgToFrm(&imgIn, &frmIn);
                frmIn.stVFrame.enCompressMode = enCompressMode;
                 ret = MppFrmResize(&frmIn, &frmDst, IMAGE_WIDTH, IMAGE_HEIGHT);// 将图片变为224*224
                ret = FrmToOrigImg(&frmDst, &imgDst);
                ret = CnnCalU8c1Img(self,  &imgDst, numInfo, sizeof(numInfo) / sizeof((numInfo)[0]), &resLen);// self = &model, &imgDst, numInfo地址，numInfo的大小，resLen
                SAMPLE_CHECK_EXPR_RET(ret < 0, ret, "CnnCalU8c1Img FAIL, ret=%#x\n", ret);
                HI_ASSERT(resLen <= sizeof(numInfo) / sizeof(numInfo[0]));

                if(objs[j].cls == 0u || numInfo[0].num == 0u || objs[j].cls == 1u ||numInfo[0].num == 1u){
                    Num_listen++;
                }else if(objs[j].cls == 2u ||numInfo[0].num == 2u){
                    Num_usecellphone++;
                }
               
                MppFrmDestroy(&frmDst);
            
            }
            //MppFrmDrawRects(dstFrm, Boxs_usecellphone, Boxs_usecellphone_index , RGB888_RED, DRAW_RETC_THICK);
        }
        All_num[0] = (char)Num_listen + '0';
        //All_num[1] = (char)Num_readbooks + '0';
        All_num[1] = (char)Num_usecellphone + '0';

        if(!(Num_listen == 0 && Num_usecellphone == 0)){
            sendAllNum(All_num);
            SAMPLE_PRT("listen & write: %d, usecellphone: %d\n", Num_listen, Num_usecellphone);
        }
        

        Num_listen = 0;
        //Num_readbooks = 0;
        Num_usecellphone = 0;
        
        IveImgDestroy(&imgIn);


    return ret;
}

#ifdef __cplusplus
#if __cplusplus

#endif
#endif /* End of #ifdef __cplusplus */
